/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.monitor.simple.pages;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.container.page.Menu;
import com.alibaba.dubbo.container.page.Page;
import com.alibaba.dubbo.container.page.PageHandler;
import com.alibaba.dubbo.monitor.MonitorService;
import com.alibaba.dubbo.monitor.simple.CountUtils;
import com.alibaba.dubbo.monitor.simple.RegistryContainer;
import com.alibaba.dubbo.monitor.simple.SimpleMonitorService;

/**
 * LZYServicesPageHandler
 * 
 * @author lvzhenyu
 */
@Menu(name = "Statistics Overview", desc = "Statistics Overview", order = Integer.MAX_VALUE - 10)
public class StatisticsOverviewPageHandler implements PageHandler {
    
    public Page handle(URL url) {
    	String fromHHmm = url.getParameter("fromhhmm");
    	if(fromHHmm==null){
    		fromHHmm="";
    	}
    	String toHHmm = url.getParameter("tohhmm");
    	if(toHHmm==null){
    		toHHmm="";
    	}
    	
    	List<ApplicationStatisticRow> rows = new ArrayList<ApplicationStatisticRow>();
    	
    	Set<String> applications = RegistryContainer.getInstance().getApplications();
    	for(String application:applications){
    		rows.add(countApplicationStatistics(application,fromHHmm,toHHmm));
    	}
    	
    	StringBuilder nav = new StringBuilder();
    	nav.append("Statistics Overview");
    	
        return new Page(nav.toString(), "Statistics Overview",
                Arrays.asList(new String[] { "Application", "Success", "Failure", "Avg Elapsed (ms)",
                        "Max Elapsed (ms)","Detail" }), sortRows(rows),form(fromHHmm,toHHmm));
    }
    
    private String form(String fromHHmm,String toHHmm){
    	StringBuilder form=new StringBuilder("");
    	form.append("<form name='form1' action='statisticsOverview.html'>");
    	form.append("From(hhmm):<input type='text' name='fromhhmm' value='"+fromHHmm+"'/>");
    	form.append("To(hhmm):<input type='text' name='tohhmm' value='"+toHHmm+"'/>");
    	form.append("<input type='submit' value='Search'/>");
    	form.append("</form>");
    	
    	return form.toString();
    }
    
    private List<List<String>> sortRows(List<ApplicationStatisticRow> rows){
    	Collections.sort(rows);
    	
    	List<List<String>> sortedRows=new ArrayList<List<String>>();
    	for(ApplicationStatisticRow applicationStatisticRow:rows){
    		sortedRows.add(this.toRow(applicationStatisticRow.getService(), applicationStatisticRow.getStatistic()));
    	}
    	return sortedRows;
    }
    
    private ApplicationStatisticRow countApplicationStatistics(String application,String fromHHmm,String toHHmm){    	
    	List<URL> applicationProviders=new ArrayList<URL>();
    	if(application!=null){
    		applicationProviders=RegistryContainer.getInstance().getProvidersByApplication(application); 
    	}
    	
    	Set<String> services=new HashSet<String>();
    	for(URL providerUrl:applicationProviders){
    		services.add(providerUrl.getServiceInterface());
    	}
    		
    	long[] applicationStatistics = newStatistics();
    	for(String service:services){
    		String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
    		String directory = SimpleMonitorService.getInstance().getStatisticsDirectory();
    		String filename = directory + "/" + date + "/" + service;
    		File serviceDir = new File(filename);
    		
    		long[] serviceStatistics = newStatistics();
            if (serviceDir.exists()) {
                File[] methodDirs = serviceDir.listFiles();
                for (File methodDir : methodDirs) {
                    long[] methodStatistics = newStatistics();
                    File[] consumerDirs = methodDir.listFiles();
                    for (File consumerDir : consumerDirs) {
                        File[] providerDirs = consumerDir.listFiles();
                        for (File providerDir : providerDirs) {
                            appendStatistics(providerDir, methodStatistics,fromHHmm,toHHmm);
                        }
                    }
                    
                    serviceStatistics[0]+=methodStatistics[0];
                    serviceStatistics[1]+=methodStatistics[1];
                    serviceStatistics[2]+=methodStatistics[2];
                    serviceStatistics[3]+=methodStatistics[3];
                    serviceStatistics[4]+=methodStatistics[4];
                    serviceStatistics[5]+=methodStatistics[5];
                    serviceStatistics[6]=Math.max(serviceStatistics[6],methodStatistics[6]);
                    serviceStatistics[7]=Math.max(serviceStatistics[7],methodStatistics[7]);
                    serviceStatistics[8]=0;//Math.max(serviceTotalStatistics[8],statistics[8])
                    serviceStatistics[9]=0;//Math.max(serviceTotalStatistics[9],statistics[9])
                }
            }
            
            applicationStatistics[0]+=serviceStatistics[0];
            applicationStatistics[1]+=serviceStatistics[1];
            applicationStatistics[2]+=serviceStatistics[2];
            applicationStatistics[3]+=serviceStatistics[3];
            applicationStatistics[4]+=serviceStatistics[4];
            applicationStatistics[5]+=serviceStatistics[5];
            applicationStatistics[6]=Math.max(applicationStatistics[6],serviceStatistics[6]);
            applicationStatistics[7]=Math.max(applicationStatistics[7],serviceStatistics[7]);
            applicationStatistics[8]=0;//Math.max(applicationStatistics[8],serviceStatistics[8])
            applicationStatistics[9]=0;//Math.max(applicationStatistics[9],serviceStatistics[9])
    	}	
    		
    	
    	return new ApplicationStatisticRow(application,applicationStatistics);        
    }
    
    private long[] newStatistics() {
        return new long[10];
    }
    
    private List<String> toRow(String name, long[] statistics) {
        List<String> row = new ArrayList<String>();
        row.add(name);
        row.add(String.valueOf(statistics[0]) + " --&gt; " + String.valueOf(statistics[1]));
        row.add(String.valueOf(statistics[2]) + " --&gt; " + String.valueOf(statistics[3]));
        row.add(String.valueOf(statistics[0] == 0 ? 0 : statistics[4] / statistics[0]) 
                + " --&gt; " + String.valueOf(statistics[1] == 0 ? 0 : statistics[5] / statistics[1]));
        row.add(String.valueOf(statistics[6]) + " --&gt; " + String.valueOf(statistics[7]));
//        row.add(String.valueOf(statistics[8]) + " --&gt; " + String.valueOf(statistics[9]));
        row.add("<a href=\"applicationStatistics.html?application="+name+"\">Detail</a>");
        return row;
    }
    
    private void appendStatistics(File providerDir, long[] statistics,String fromHHmm,String toHHmm) {
        statistics[0] += CountUtils.sum(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.SUCCESS),fromHHmm,toHHmm);
        statistics[1] += CountUtils.sum(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.SUCCESS),fromHHmm,toHHmm);
        statistics[2] += CountUtils.sum(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.FAILURE),fromHHmm,toHHmm);
        statistics[3] += CountUtils.sum(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.FAILURE),fromHHmm,toHHmm);
        statistics[4] += CountUtils.sum(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.ELAPSED),fromHHmm,toHHmm);
        statistics[5] += CountUtils.sum(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.ELAPSED),fromHHmm,toHHmm);
        statistics[6] = Math.max(statistics[6], CountUtils.max(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.MAX_ELAPSED),fromHHmm,toHHmm));
        statistics[7] = Math.max(statistics[7], CountUtils.max(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.MAX_ELAPSED),fromHHmm,toHHmm));
        statistics[8] = Math.max(statistics[8], CountUtils.max(new File(providerDir, MonitorService.CONSUMER + "." + MonitorService.MAX_CONCURRENT),fromHHmm,toHHmm));
        statistics[9] = Math.max(statistics[9], CountUtils.max(new File(providerDir, MonitorService.PROVIDER + "." + MonitorService.MAX_CONCURRENT),fromHHmm,toHHmm));
    }
    
    class ApplicationStatisticRow implements Comparable<ApplicationStatisticRow>{
    	private String application;
    	private long[] statistic;
    	
    	public ApplicationStatisticRow(String service,long[] statistic){
    		this.application=service;
    		this.statistic=statistic;
    	}

    	public String getService() {
    		return application;
    	}

    	public long[] getStatistic() {
    		return statistic;
    	}

    	public int compareTo(ApplicationStatisticRow o2) {
    		//调用频繁的排在前面
    		if(statistic[0]<o2.statistic[0]){
    			return 1;
    		}else if(statistic[0]>o2.statistic[0]){
    			return -1;
    		}
    		return 0;
    	}

    }

}